package com.sdleyou.treepro.common.service.impl;

import com.sdleyou.treepro.common.exception.ServiceException;
import com.sdleyou.treepro.common.model.convert.UserMissionDO2UserMissionVOConverter;
import com.sdleyou.treepro.common.model.dao.UserDO;
import com.sdleyou.treepro.common.model.dao.UserMissionDO;
import com.sdleyou.treepro.common.model.dto.MissionRewardDTO;
import com.sdleyou.treepro.common.model.enums.ErrorCodeEnum;
import com.sdleyou.treepro.common.model.enums.RedisLockEnum;
import com.sdleyou.treepro.common.model.vo.MissionVO;
import com.sdleyou.treepro.common.model.vo.UserMissionVO;
import com.sdleyou.treepro.common.rabbitmq.AmqpExchange;
import com.sdleyou.treepro.common.rabbitmq.message.StepChangeMsg;
import com.sdleyou.treepro.common.service.*;
import com.sdleyou.treepro.common.utils.DateUtil;
import org.apache.http.util.TextUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class UserMissionManagerImpl implements UserMissionManager {

    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private MongoPageManager mongoPageManager;
    @Autowired
    private UserPropManager userPropManager;
    @Autowired
    private MissionManager missionManager;
    @Autowired
    private UserAchievementManager userAchievementManager;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private RedissonClient redissonClient;

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 当前完成任务情况
     * @param userId
     * @return
     */
    @Override
    public List<UserMissionVO> getMissionInfo(String userId) {
        Query query = new Query(Criteria.where("user_id").is(userId).and("task_tag").in("day", "permanent")).with(Sort.by(Sort.Order.asc("sort")));
        List<UserMissionDO> userMissionDOS = mongoTemplate.find(query, UserMissionDO.class);
        return userMissionDOS.stream().map(UserMissionDO2UserMissionVOConverter::convert).collect(Collectors.toList());
    }

    /**
     * 获取某一任务完成情况
     */
    @Override
    public UserMissionVO getOneMissionInfo(String userId, String type) {
        Query query = new Query(Criteria.where("user_id").is(userId).and("task_type").is(type));
        UserMissionDO user = mongoTemplate.findOne(query, UserMissionDO.class);
        if(user != null){
            UserMissionVO userMissionVO = new UserMissionVO();
            BeanUtils.copyProperties(user, userMissionVO);
            return userMissionVO;
        }else {
            return null;
        }

    }

    /**
     * 更改任务状态
     * @param userId
     * @param type
     * @return
     */
    @Override
    public Map<String, String> updateMission(String userId, String type, Integer param) {
        Query query = new Query(Criteria.where("user_id").is(userId));
        UserDO userDO = mongoTemplate.findOne(query, UserDO.class);
        if(userDO == null){
            throw new ServiceException(ErrorCodeEnum.E100.code(), "用户不存在");
        }
        UserMissionVO missionInfo = getOneMissionInfo(userId, type);
        if(missionInfo == null){
            throw new ServiceException(ErrorCodeEnum.E106.code(), "该任务不存在");
        }
        Update update = new Update();
        if("sign".equals(type)){
            updateOnceMission(userId, type, update);
        }else if("step".equals(type)){
            //捐赠步数任务
            //道具水滴+5
            Query q = new Query(Criteria.where("user_id").is(userId).and("task_type").is(type));
            update.set("current_condition", param);
            int totalNum = Integer.parseInt(missionInfo.getCondition());//3
            if(param >= totalNum) {
                update.set("is_finish", true);
                update.set("can_receive", true);
            }
            mongoTemplate.updateFirst(q, update, UserMissionDO.class);
        }else if("water".equals(type)){
            //浇水任务 最多3次
            //道具水滴+5
            updateTimesMission(userId, type, missionInfo, update);
        }else if("fertilizer".equals(type)){
            //施肥任务 最多3次
            //道具肥料+10
            updateTimesMission(userId, type, missionInfo, update);
        }else if("pest".equals(type)){
            //除虫任务 最多3次
            //水滴+10
            updateTimesMission(userId, type, missionInfo, update);
        }else if("adv".equals(type)){
            //看广告任务
            //水滴+10，肥料+10
            updateTimesMission(userId, type, missionInfo, update);
        }else if("share".equals(type)){
            //分享任务
            //道具水滴+5
            Query queryUserMission = new Query(Criteria.where("user_id").is(userId).and("task_type").is(type));
            UserMissionDO user = mongoTemplate.findOne(queryUserMission, UserMissionDO.class);
            if(DateUtil.getHourTime(user.getGmtModified())==0){
                throw new ServiceException(ErrorCodeEnum.E107.code(), "一小时内只能分享一次");
            }
            updateTimesMission(userId, type, missionInfo, update);
        }else if("invent".equals(type)){
            //邀请好友任务
            //道具水滴+30，肥料+10
            Query q = new Query(Criteria.where("user_id").is(userId).and("task_type").is(type));
            UserMissionDO userMission = mongoTemplate.findOne(q, UserMissionDO.class);
            if (userMission != null) {
                update.set("is_finish", true);
                update.set("can_receive", true);
                update.set("is_receive", false);
                update.set("total", userMission.getTotal()+1);
            }
            mongoTemplate.updateFirst(q, update, UserMissionDO.class);
        }else if("recall".equals(type)){
            //召回好友任务
            updateTimesMission(userId, type, missionInfo, update);
        }else if("feed".equals(type)){
            //给小助手喂食任务
            updateTimesMission(userId, type, missionInfo, update);
        }else if("signature".equals(type)){
            //生成日签任务
            updateOnceMission(userId, type, update);
        }else if("noon".equals(type)){
            //中午登陆查看任务
            updateOnceMission(userId, type, update);
        }
        return null;
    }

    /**
     * 更新日常一次性任务 签到看广告等
     * @param userId
     * @param type
     * @param update
     */
    private void updateOnceMission(String userId, String type, Update update) {
        Query q = new Query(Criteria.where("user_id").is(userId).and("task_type").is(type));
        update.set("is_finish", true);
        update.set("can_receive", true);
        mongoTemplate.updateFirst(q, update, UserMissionDO.class);
    }

    /**
     * 更新日常数次任务 如一日可完成3次
     * @param userId
     * @param type
     * @param missionInfo
     * @param update
     */
    private void updateTimesMission(String userId, String type, UserMissionVO missionInfo, Update update) {
        if (missionInfo.getCurrentCondition() != null && missionInfo.getCondition() != null) {
            int totalNum = Integer.parseInt(missionInfo.getCondition());
            int currentNum = Integer.parseInt(missionInfo.getCurrentCondition());
            if (currentNum >= 0 && currentNum < totalNum) {
                Query q = new Query(Criteria.where("user_id").is(userId).and("task_type").is(type));
                UserMissionDO one = mongoTemplate.findOne(q, UserMissionDO.class);
                if (one != null && !one.getIsFinish()) {
                    update.set("is_finish", true);
                    update.set("can_receive", true);
                    update.set("current_condition", currentNum + 1);
                    update.set("gmt_modified", DateUtil.getDateline());
                    mongoTemplate.updateFirst(q, update, UserMissionDO.class);
                }
            }
        }
    }

    /**
     * 更新日常次数限制任务 浇水施肥除虫等
     * @param userId
     * @param type
     * @param missionInfo
     * @param update
     */
    private void updateTimeMission(String userId, String type, UserMissionVO missionInfo, Update update) {
        if (!missionInfo.getIsReceive()) {
            if (missionInfo.getCurrentCondition() != null && missionInfo.getCondition() != null) {
                int totalNum = Integer.parseInt(missionInfo.getCondition());//3
                int currentNum = Integer.parseInt(missionInfo.getCurrentCondition()); //0 1 2
                //更新任务状态
                if (currentNum < totalNum - 1) {
                    update.set("current_condition", currentNum + 1);
                    Query q = new Query(Criteria.where("user_id").is(userId).and("task_type").is(type));
                    mongoTemplate.updateFirst(q, update, UserMissionDO.class);
                } else if (currentNum == totalNum - 1) {
                    update.set("is_finish", true);
                    update.set("can_receive", true);
                    update.set("current_condition", currentNum + 1);
                    Query q = new Query(Criteria.where("user_id").is(userId).and("task_type").is(type));
                    mongoTemplate.updateFirst(q, update, UserMissionDO.class);
                }
            }
        }
    }

    /**
     * 完成任务
     * sign-签到任务 step-捐赠步数任务 water-浇水任务 fertilizer-施肥任务 pest-除虫任务 adv-广告任务 share-分享任务 invent-邀请好友任务
     * @param userId
     * @param type
     * @return
     */
    @Override
    public Map<String, String> finishMission(String userId, String type, Integer multiple) {
        if(multiple==null){
            multiple = 1;
        }
        Query queryUser = new Query(Criteria.where("user_id").is(userId));
        Query query = new Query(Criteria.where("user_id").is(userId).and("task_type").is(type));
        UserDO userDO = mongoTemplate.findOne(queryUser, UserDO.class);
        if(userDO == null){
            throw new ServiceException(ErrorCodeEnum.E100.code(), "用户不存在");
        }
        UserMissionVO missionInfo = getOneMissionInfo(userId, type);
        if(missionInfo == null){
            throw new ServiceException(ErrorCodeEnum.E106.code(), "该任务不存在");
        }
        if(missionInfo.getIsReceive()){
            throw new ServiceException(ErrorCodeEnum.E105.code(), "今日任务已完成");
        }
        if(!missionInfo.getIsFinish()){
            throw new ServiceException(ErrorCodeEnum.E108.code(), "任务还未完成");
        }

        Update update = new Update();
        if("sign".equals(type)){
            //签到任务
            //道具水滴+5，肥料+5 干粮+1 除虫剂+1
            //增加道具数量
            long startTime = DateUtil.startOfTodDay()+18000;
            long endTime = DateUtil.startOfTodDay()+28800;
            if(DateUtil.inRangeOf(startTime, endTime)){
                //早上5点-8点，道具翻倍
                multiple *= 2;
            }
            return finishOnceMission(userId, multiple, missionInfo, update, query);
        }else if("step".equals(type)){
            //捐赠步数任务
            //道具水滴+5
            //增加道具数量
            if(!TextUtils.isEmpty(missionInfo.getCurrentCondition())){
                //更新总步数
                //userAchievementManager.updateTotalStep(Long.valueOf(missionInfo.getCurrentCondition()));
                this.amqpTemplate.convertAndSend(AmqpExchange.TOTAL_STEP_CHANGE, AmqpExchange.TOTAL_STEP_CHANGE + "_ROUTING", new StepChangeMsg(Long.valueOf(missionInfo.getCurrentCondition())));
            }
            return finishOnceMission(userId, multiple, missionInfo, update, query);
        }else if("water".equals(type)){
            //浇水任务 最多3次
            //道具水滴+5
            return finishTimesMission(userId, multiple, missionInfo, update, query);
        }else if("fertilizer".equals(type)){
            //施肥任务 最多3次
            //道具肥料+10
            return finishTimesMission(userId, multiple, missionInfo, update, query);
        }else if("pest".equals(type)){
            //除虫任务 最多3次
            //水滴+10
            return finishTimesMission(userId, multiple, missionInfo, update, query);
        }else if("adv".equals(type)){
            //看广告任务
            //水滴+10，肥料+10
            //增加道具数量
            return finishTimesMission(userId, multiple, missionInfo, update, query);
        }else if("share".equals(type)){
            //分享任务
            //道具水滴+5
            return finishTimesMission(userId, multiple, missionInfo, update, query);
        }else if("invent".equals(type)){
            //邀请好友任务
            //道具水滴+30，肥料+10
            return getStringStringMap(userId, type, multiple, query, missionInfo, update);
        }else if("recall".equals(type)){
            //召回好友任务
            return finishTimesMission(userId, multiple, missionInfo, update, query);
        }else if("feed".equals(type)){
            //给小助手喂食任务
            return finishTimesMission(userId, multiple, missionInfo, update, query);
        }else if("signature".equals(type)){
            //生成日签任务
            return finishOnceMission(userId, multiple, missionInfo, update, query);
        }else if("noon".equals(type)){
            //中午登陆查看任务
            return finishOnceMission(userId, multiple, missionInfo, update, query);
        }else if("firstLogin".equals(type)){
            //更新用户信息
            Update u = new Update();
            u.set("is_receive_first_login", true);
            mongoTemplate.updateFirst(queryUser, u, UserDO.class);
            //首次登陆奖励
            return finishOnceMission(userId, multiple, missionInfo, update, query);
        }
        return null;
    }

    /**
     * 完成永久性任务
     * @param userId
     * @param type
     * @param multiple
     * @param query
     * @param missionInfo
     * @param update
     * @return
     */
    private Map<String, String> getStringStringMap(String userId, String type, Integer multiple, Query query, UserMissionVO missionInfo, Update update) {
        Query q = new Query(Criteria.where("user_id").is(userId).and("task_type").is(type));
        UserMissionDO userMission = mongoTemplate.findOne(q, UserMissionDO.class);
        if (userMission != null) {
            if(userMission.getTotal()-1<=0){
                update.set("can_receive", false);
                update.set("is_finish", false);
                //永久没有已领取状态
                //update.set("is_receive", true);
            }
            update.set("total", userMission.getTotal()-1);
            mongoTemplate.updateFirst(query, update, UserMissionDO.class);
        }
        return setProps(userId, multiple, missionInfo);
    }

    /**
     * 完成日常数次任务 如一日可完成3次
     * @param userId
     * @param multiple
     * @param missionInfo
     * @param update
     * @return
     */
    private Map<String, String> finishTimesMission(String userId, Integer multiple, UserMissionVO missionInfo, Update update, Query query) {
        Map<String, String> map = new HashMap<>();
        if(!missionInfo.getIsReceive()) {
            if (missionInfo.getCurrentCondition() != null && missionInfo.getCondition() != null) {
                int totalNum = Integer.parseInt(missionInfo.getCondition());
                int currentNum = Integer.parseInt(missionInfo.getCurrentCondition());
                if(currentNum>=0 && currentNum<=totalNum){
                    if(currentNum==totalNum) {
                        update.set("is_receive", true);
                    }
                    update.set("can_receive", false);
                    update.set("is_finish", false);
                    map = setProps(userId, multiple, missionInfo);
                    mongoTemplate.updateFirst(query, update, UserMissionDO.class);
                }
            }
        }
        return map;
    }

    /**
     * 完成日常一次性任务 签到看广告等
     * @param userId
     * @param multiple
     * @param missionInfo
     * @param update
     */
    private Map<String, String> finishOnceMission(String userId, Integer multiple, UserMissionVO missionInfo, Update update, Query query) {
        //增加道具
        Map<String, String> map = setProps(userId, multiple, missionInfo);
        //更新任务状态
        update.set("is_receive", true);
        update.set("is_finish", false);
        update.set("can_receive", false);
        mongoTemplate.updateFirst(query, update, UserMissionDO.class);
        return map;
    }

    /**
     * 完成日常次数限制任务 浇水施肥除虫等
     * @param userId
     * @param multiple
     * @param missionInfo
     * @param update
     * @return
     */
    private Map<String, String> finishTimeMission(String userId, Integer multiple, UserMissionVO missionInfo, Update update, Query query) {
        Map<String, String> map = new HashMap<>();
        if(missionInfo.getCurrentCondition()!=null && missionInfo.getCondition()!=null){
            int totalNum = Integer.parseInt(missionInfo.getCondition());//3
            int currentNum = Integer.parseInt(missionInfo.getCurrentCondition()); //0 1 2
            //更新任务状态
            if(currentNum == totalNum){
                update.set("is_receive", true);
                update.set("is_finish", false);
                update.set("can_receive", false);
                map = setProps(userId, multiple, missionInfo);
            }
        }
        mongoTemplate.updateFirst(query, update, UserMissionDO.class);
        return map;
    }

    /**
     * 增加道具并设置返回值
     * @param userId
     * @param multiple
     * @param missionInfo
     */
    private Map<String, String> setProps(String userId, Integer multiple, UserMissionVO missionInfo) {
        Map<String, String> map = new HashMap<>();
        List<MissionRewardDTO> propList = missionInfo.getPropList();
        for (MissionRewardDTO missionRewardDTO : propList){
            if(missionRewardDTO!=null && missionRewardDTO.getPropNumber()!=null){
                String propType = missionRewardDTO.getPropType();
                Integer propNum = Integer.parseInt(missionRewardDTO.getPropNumber()) * multiple;
                userPropManager.addProp(userId, propType, propNum);
                map.put(propType, propNum * multiple+"");
            }
        }
        return map;
    }

    /**
     * 更新个人任务状态
     * 新用户登陆用
     */
    @Override
    public void updateMission(String userId){
        Query q = new Query(Criteria.where("user_id").is(userId));
        UserMissionDO user = mongoTemplate.findOne(q, UserMissionDO.class);
        if(user==null) {
            List<MissionVO> missionList = missionManager.getMissionList();
            for (MissionVO missionVO : missionList) {
                if (missionVO != null) {
                    UserMissionDO userMissionDO = new UserMissionDO();
                    BeanUtils.copyProperties(missionVO, userMissionDO);
                    userMissionDO.setUserId(userId);
                    userMissionDO.setCurrentCondition("0");
                    if (userMissionDO.getTaskType().equals("sign") || userMissionDO.getTaskType().equals("firstLogin")){
                        userMissionDO.setIsFinish(true);
                        userMissionDO.setCanReceive(true);
                    }else {
                        userMissionDO.setIsFinish(false);
                        userMissionDO.setCanReceive(false);
                    }
                    userMissionDO.setIsReceive(false);
                    userMissionDO.setTotal(0);
                    userMissionDO.setGmtCreate(DateUtil.getDateline());
                    userMissionDO.setGmtModified(DateUtil.getDateline());
                    mongoTemplate.insert(userMissionDO);
                }
            }
        }
    }

    /**
     * 每日0点更新任务完成情况
     */
    @Override
    public void updateMission() {
        List<UserMissionDO> all = mongoTemplate.findAll(UserMissionDO.class);
        for (UserMissionDO userMissionDO : all){
            if(userMissionDO!=null){
                Update update = new Update();
                if ("sign".equals(userMissionDO.getTaskType())){
                    update.set("is_finish", true);
                    update.set("can_receive", true);
                }else if("invent".equals(userMissionDO.getTaskType()) || userMissionDO.getTaskType().equals("firstLogin")){
                    continue;
                } else {
                    update.set("is_finish", false);
                    update.set("can_receive", false);
                }
                update.set("is_receive", false);
                update.set("current_condition", 0);
                update.set("gmt_modified", DateUtil.getDateline());
                Query query = new Query(Criteria.where("task_id").is(userMissionDO.getTaskId()).and("user_id").is(userMissionDO.getUserId()));
                mongoTemplate.updateFirst(query, update, UserMissionDO.class);
            }
        }
    }

    /**
     * 更新任务信息
     */
    @Override
    public void update(String userId) {
        List<MissionVO> missionVOS = missionManager.getMissionList();
            for (MissionVO missionVO : missionVOS){
            if(missionVO!=null){
                Query query = new Query(Criteria.where("user_id").is(userId).and("task_type").is(missionVO.getTaskType()));
                UserMissionDO one = mongoTemplate.findOne(query, UserMissionDO.class);
                if(one!=null){
                    Update update = new Update();
                    update.set("task_name", missionVO.getTaskName());
                    update.set("task_img", missionVO.getTaskImg());
                    update.set("task_tag", missionVO.getTaskTag());
                    update.set("task_desc", missionVO.getTaskDesc());
                    update.set("condition", missionVO.getCondition());
                    update.set("propList", missionVO.getPropList());
                    mongoTemplate.updateFirst(query, update, UserMissionDO.class);
                }else {
                    UserMissionDO userMissionDO = new UserMissionDO();
                    BeanUtils.copyProperties(missionVO, userMissionDO);
                    userMissionDO.setUserId(userId);
                    userMissionDO.setCurrentCondition("0");
                    if (userMissionDO.getTaskType().equals("sign") || userMissionDO.getTaskType().equals("firstLogin")){
                        userMissionDO.setIsFinish(true);
                        userMissionDO.setCanReceive(true);
                    }else {
                        userMissionDO.setIsFinish(false);
                        userMissionDO.setCanReceive(false);
                    }
                    userMissionDO.setIsReceive(false);
                    userMissionDO.setTotal(0);
                    userMissionDO.setGmtCreate(DateUtil.getDateline());
                    userMissionDO.setGmtModified(DateUtil.getDateline());
                    mongoTemplate.insert(userMissionDO);
                }
            }
        }
    }

    /**
     * 更新全部任务信息
     */
    @Override
    public void updateAll(){
        List<UserDO> userDOS = mongoTemplate.find(new Query(), UserDO.class);
        for (UserDO serDO : userDOS) {
            if(serDO!=null){
                List<MissionVO> missionVOS = missionManager.getMissionList();
                for (MissionVO missionVO : missionVOS){
                    if(missionVO!=null){
                        Query query = new Query(Criteria.where("user_id").is(serDO.getUserId()).and("task_type").is(missionVO.getTaskType()));
                        UserMissionDO one = mongoTemplate.findOne(query, UserMissionDO.class);
                        if(one!=null){
                            Update update = new Update();
                            update.set("task_name", missionVO.getTaskName());
                            update.set("task_img", missionVO.getTaskImg());
                            update.set("task_tag", missionVO.getTaskTag());
                            update.set("task_desc", missionVO.getTaskDesc());
                            update.set("condition", missionVO.getCondition());
                            update.set("propList", missionVO.getPropList());
                            update.set("sort", missionVO.getSort());
                            mongoTemplate.updateFirst(query, update, UserMissionDO.class);
                        }else {
                            UserMissionDO userMissionDO = new UserMissionDO();
                            BeanUtils.copyProperties(missionVO, userMissionDO);
                            userMissionDO.setUserId(serDO.getUserId());
                            userMissionDO.setCurrentCondition("0");
                            if (userMissionDO.getTaskType().equals("sign") || userMissionDO.getTaskType().equals("firstLogin")){
                                userMissionDO.setIsFinish(true);
                                userMissionDO.setCanReceive(true);
                            }else {
                                userMissionDO.setIsFinish(false);
                                userMissionDO.setCanReceive(false);
                            }
                            userMissionDO.setIsReceive(false);
                            userMissionDO.setTotal(0);
                            userMissionDO.setGmtCreate(DateUtil.getDateline());
                            userMissionDO.setGmtModified(DateUtil.getDateline());
                            mongoTemplate.insert(userMissionDO);
                        }
                    }
                }
            }
        }
    }

    /**
     * 查询首次登陆奖励情况
     * @param userId
     */
    @Override
    public UserMissionVO getFirstLoginInfo(String userId) {
        Query query = new Query(Criteria.where("user_id").is(userId).and("task_type").is("firstLogin"));
        UserMissionDO user = mongoTemplate.findOne(query, UserMissionDO.class);
        if(user != null){
            UserMissionVO userMissionVO = new UserMissionVO();
            BeanUtils.copyProperties(user, userMissionVO);
            return userMissionVO;
        }else {
            return null;
        }
    }
}
